package cn.legend.travel.admin.authorize.service.impl;

import cn.legend.travel.admin.authorize.dao.cache.IUserCacheRepository;
import cn.legend.travel.admin.authorize.dao.persist.repository.*;
import cn.legend.travel.admin.authorize.pojo.entity.Role;
import cn.legend.travel.admin.authorize.pojo.entity.RoleFrontendMenu;
import cn.legend.travel.admin.authorize.pojo.entity.User;
import cn.legend.travel.admin.authorize.pojo.param.RoleAddNewParam;
import cn.legend.travel.admin.authorize.pojo.param.RoleUpdateParam;
import cn.legend.travel.admin.authorize.pojo.param.UserUpdateParam;
import cn.legend.travel.admin.authorize.pojo.vo.BackendApiStandardVO;
import cn.legend.travel.admin.authorize.pojo.vo.RoleAndPermissionVO;
import cn.legend.travel.admin.authorize.pojo.vo.RoleStandardVO;
import cn.legend.travel.admin.authorize.service.IRoleService;
import cn.legend.travel.common.enumerator.ServiceCode;
import cn.legend.travel.common.exception.ServiceException;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;


@Service
@RequiredArgsConstructor
public class RoleServiceImpl implements IRoleService {
    private final IUserRepository userRepository;
    private final IUserCacheRepository userCacheRepository;
    private final IRoleRepository roleRepository;
    private final IBackendApiRepository backendApiRepository;
    private final IRoleBackendApiRepository roleBackendApiRepository;
    private final IRoleFrontendMenuRepository roleFrontendMenuRepository;

    @Override
    public List<RoleAndPermissionVO> getAll() {
        return roleRepository.getAll();
    }

    @Override
    public void addNewPermission(Long roleId, Long apiId) {
        BackendApiStandardVO api = backendApiRepository.getById(apiId);
        if (api == null) {
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, "添加失败,该权限不存在");
        }

        RoleStandardVO role = roleRepository.getRoleById(roleId);
        if (role == null) {
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, "添加失败,该角色不存在");
        }

        int row = roleBackendApiRepository.countByRoleIdAndApiId(roleId, apiId);
        if (row != 0) {
            throw new ServiceException(ServiceCode.ERROR_CONFLICT, "添加失败,该角色已有该权限");
        }

        // 添加权限前添加相应的前端菜单
        RoleFrontendMenu roleMenu = roleFrontendMenuRepository.getByMenuId(roleId, api.getMenuId());
        if (roleMenu == null) {
            row = roleFrontendMenuRepository.insert(roleId, api.getMenuId());
            if (row != 1) {
                throw new ServiceException(ServiceCode.ERROR_INSERT, "服务器忙,请稍后再试");
            }
        }

        row = roleBackendApiRepository.addNewPermission(roleId, apiId);
        if (row != 1) {
            throw new ServiceException(ServiceCode.ERROR_INSERT, "服务器忙,请稍后再试");
        }
        kickOut(roleId);
    }

    @Override
    @Transactional
    public void deletePermission(Long roleId, Long apiId) {
        BackendApiStandardVO api = backendApiRepository.getById(apiId);
        if (api == null) {
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, "删除失败,该权限不存在");
        }

        RoleStandardVO role = roleRepository.getRoleById(roleId);
        if (role == null) {
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, "删除失败,该角色不存在");
        }

        int row = roleBackendApiRepository.countByRoleIdAndApiId(roleId, apiId);
        if (row == 0) {
            throw new ServiceException(ServiceCode.ERROR_CONFLICT, "删除失败,该角色已没有该权限");
        }

        row = roleBackendApiRepository.deletePermission(roleId, apiId);
        if (row != 1) {
            throw new ServiceException(ServiceCode.ERROR_DELETE, "服务器忙,请稍后再试");
        }

        row = roleBackendApiRepository.getByRoleAndMenuId(roleId, api.getMenuId());
        if (row == 0) {
            row = roleFrontendMenuRepository.deleteByRoleAndMenu(roleId, api.getMenuId());
            if (row != 1) {
                throw new ServiceException(ServiceCode.ERROR_DELETE, "服务器忙,请稍后再试");
            }
        }
        kickOut(roleId);
    }

    @Override
    public void addNew(RoleAddNewParam param) {
        Role role = roleRepository.getRoleByName(param.getName());
        if (role != null) {
            throw new ServiceException(ServiceCode.ERROR_CONFLICT, "已有该角色名,请换个角色名重试");
        }
        int row = roleRepository.addNew(param);
        if (row != 1) {
            throw new ServiceException(ServiceCode.ERROR_INSERT, "服务器忙,请稍后再试");
        }
    }

    @Override
    public void update(RoleUpdateParam param) {
        RoleStandardVO role = roleRepository.getRoleById(param.getId());
        if (role == null) {
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, "更改失败,该角色不存在");
        }
        int row = roleRepository.update(param);
        if (row != 1) {
            throw new ServiceException(ServiceCode.ERROR_UPDATE, "服务器忙,请稍后再试");
        }
        kickOut(role.getId());
    }

    /**
     * 根据角色id删除角色，同时删除角色权限关联表的关联数据
     *
     * @param roleId 角色id
     */
    @Override
    @Transactional
    public void delete(Long roleId) {
        RoleStandardVO role = roleRepository.getRoleById(roleId);
        if (role == null) {
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, "删除失败,该角色已不存在");
        }

        int row = roleRepository.delete(roleId);
        if (row != 1) {
            throw new ServiceException(ServiceCode.ERROR_UPDATE, "服务器忙,请稍后再试");
        }

        roleBackendApiRepository.deleteByRoleId(roleId);
        row = roleBackendApiRepository.countByRoleId(roleId);
        if (row != 0) {
            throw new ServiceException(ServiceCode.ERROR_UPDATE, "服务器忙,请稍后再试");
        }
        List<User> users = userRepository.getByRoleId(roleId);
        users.forEach(user -> {
            user.setRoleId(2L);
            UserUpdateParam updateParam = new UserUpdateParam();
            updateParam.setDescription("普通管理员");
            BeanUtils.copyProperties(user, updateParam);
            userRepository.update(updateParam);
        });
        kickOut(roleId);
    }

    /**
     * 更改角色后与之相关的管理员会被踢下线
     *
     * @param roleId 角色id
     */
    private void kickOut(Long roleId) {
        List<User> users = userRepository.getByRoleId(roleId);
        users.forEach(user -> userCacheRepository.delete(user.getId()));
    }
}
